package util;

import exceptions.SemanticException;

import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

public interface Utils {

    /**
     * 倒序遍历链表，寻找倒数第一个具有指定 identifier 的 Var
     *
     * @param list       需要遍历的链表
     * @param identifier 指定 identifier
     * @return 倒数第一个具有指定 identifier 的 Var，如果不存在，那么返回 null
     */
    static Var findLastOf(LinkedList<Var> list, String identifier) {
        ListIterator<Var> it = list.listIterator(list.size());
        while (it.hasPrevious()) {
            Var ret = it.previous();
            if (ret.identifier.equals(identifier)) return ret;
        }
        return null;
    }

    /**
     * 根据形式化表达式的语义，构造新的表达式
     *
     * @param expr1 左表达式
     * @param type  运算类型
     * @param expr2 右表达式
     * @return 根据语义构造新的表达式
     */
    static Var makeVarAsExpression(Var expr1, int type, Var expr2) {
        switch (type) {
            case TokenType.PLUS:
                return new Var(Var.Type.BasicType.INTEGER, String.format("(%s + %s)", expr1.identifier, expr2.identifier));
            case TokenType.MINUS:
                return new Var(Var.Type.BasicType.INTEGER, String.format("(%s - %s)", expr1.identifier, expr2.identifier));
            case TokenType.TIMES:
                return new Var(Var.Type.BasicType.INTEGER, String.format("(%s * %s)", expr1.identifier, expr2.identifier));
            case TokenType.DIVIDE:
                return new Var(Var.Type.BasicType.INTEGER, String.format("(%s DIV %s)", expr1.identifier, expr2.identifier));
            case TokenType.MOD:
                return new Var(Var.Type.BasicType.INTEGER, String.format("(%s MOD %s)", expr1.identifier, expr2.identifier));
            case TokenType.AND:
                return new Var(Var.Type.BasicType.BOOLEAN, String.format("(%s & %s)", expr1.identifier, expr2.identifier));
            case TokenType.OR:
                return new Var(Var.Type.BasicType.BOOLEAN, String.format("(%s OR %s)", expr1.identifier, expr2.identifier));
            case TokenType.NOT:
                return new Var(Var.Type.BasicType.BOOLEAN, String.format("(~ %s)", expr2.identifier));
            case TokenType.EQ:
                return new Var(Var.Type.BasicType.BOOLEAN, String.format("(%s = %s)", expr1.identifier, expr2.identifier));
            case TokenType.NEQ:
                return new Var(Var.Type.BasicType.BOOLEAN, String.format("(%s # %s)", expr1.identifier, expr2.identifier));
            case TokenType.LT:
                return new Var(Var.Type.BasicType.BOOLEAN, String.format("(%s < %s)", expr1.identifier, expr2.identifier));
            case TokenType.LE:
                return new Var(Var.Type.BasicType.BOOLEAN, String.format("(%s <= %s)", expr1.identifier, expr2.identifier));
            case TokenType.GT:
                return new Var(Var.Type.BasicType.BOOLEAN, String.format("(%s > %s)", expr1.identifier, expr2.identifier));
            case TokenType.GE:
                return new Var(Var.Type.BasicType.BOOLEAN, String.format("(%s >= %s)", expr1.identifier, expr2.identifier));

            default:
                throw new UnsupportedOperationException("makeVarAsExpression");
        }
    }

    /**
     * 根据形式化表达式的语义，判断表达式是否是合法的
     *
     * @param expr1 左表达式
     * @param type  运算类型
     * @param expr2 右表达式
     * @return 表达式是合法的
     */
    static boolean isLegalTypeAsExpression(Var expr1, int type, Var expr2) {
        switch (type) {
            case TokenType.PLUS, TokenType.MINUS, TokenType.TIMES, TokenType.DIVIDE, TokenType.MOD:
                return expr1.type.basicType == Var.Type.BasicType.INTEGER && expr2.type.basicType == Var.Type.BasicType.INTEGER;
            case TokenType.AND, TokenType.OR:
                return expr1.type.basicType == Var.Type.BasicType.BOOLEAN && expr2.type.basicType == Var.Type.BasicType.BOOLEAN;
            case TokenType.NOT:
                return expr1 == null && expr2.type.basicType == Var.Type.BasicType.BOOLEAN;
            case TokenType.EQ, TokenType.NEQ, TokenType.LT, TokenType.LE, TokenType.GT, TokenType.GE:
                return expr1.type.basicType == Var.Type.BasicType.INTEGER && expr2.type.basicType == Var.Type.BasicType.INTEGER;
            default:
                throw new UnsupportedOperationException("isIllegalType");
        }
    }

    /**
     * 解码 selector 返回的动作列表
     *
     * @param now     解码起点
     * @param list    动作列表
     * @param builder 构建 identifier, 如果为 null 则不构建
     * @return 解码后的 Var
     * @throws SemanticException
     */
    static Var decodeSelector(Var now, List<Object> list, StringBuilder builder) throws SemanticException {
        for (Object obj : list) { // 遍历 selector 列表
            if (obj instanceof String) { // 取成员，r.m
                if (now.type.basicType != Var.Type.BasicType.RECORD)
                    throw new SemanticException("语义错误：对非 record 取成员");
                now = Utils.findLastOf(now.type.follow, (String) obj);
                if (now == null) throw new SemanticException("语义错误：没有找到对应成员");
                if (builder != null) builder.append(String.format(".%s", (String) obj));
            } else if (obj instanceof Var) { // 取地址，a[e]
                if (now.type.basicType != Var.Type.BasicType.ARRAY)
                    throw new SemanticException("语义错误：对非 array 取地址");
                now = now.type.follow.getFirst();
                if (builder != null) builder.append(String.format("[%s]", ((Var) obj).identifier));
            } else {
                throw new SemanticException("语义错误：selector 的元素既不是 String 又不是 Var");
            }
        }
        return now;
    }
}
